package com.journaldev.concurrent;

import java.util.concurrent.atomic.AtomicInteger;

/**
 * 这里首先复习一下突然想到的一点基础知识：
 * static静态的，就是全局的，当类加载时即初始化；公共区域。
 * final是最终的，当修饰基本类型的只能进行一次赋值；如果是对象则可对其成员二次赋值，但对象地址不可变。
 *
 * ThreadLocal源码分析及内存泄漏预防
 * https://www.cnblogs.com/java-chen-hao/p/10059735.html
 * 看了两天终于看懂了
 *
 *
 * 这里需要验证一下线程只有一个threadLocals，通过不同key存入ThreadId
 *
 *
 *
 * @author: chenhs
 * @date: Created in 6:24 2019/9/23
 **/
public class ThreadLocalDemo {

    public static void main(String[] args) {
        for (int i = 0; i < 5; i++) {
            final Thread t = new Thread() {
                @Override
                public void run() {
                    System.out.println("当前线程："+ Thread.currentThread().getName()+"，已分配ID："+ ThreadId.get() + ", 已分配ID2:"+ThreadId2.get());
                }
            };
            t.start();
        }
    }


    static class ThreadId {
        /** 一个递增的序列，使用AtomicInger原子变量保证线程安全 */
        private static final AtomicInteger nextId = new AtomicInteger(0);

        /** 线程本地变量，为每个线程关联一个唯一的序号 */
        private static final ThreadLocal<Integer> threadId = new ThreadLocal<Integer>(){
            @Override
            protected Integer initialValue() {
                /** 相当于nextId++,由于nextId++这种操作是个复合操作而非原子操作，
                 会有线程安全问题(可能在初始化时就获取到相同的ID，所以使用原子变量 */
                return nextId.getAndIncrement();
            }
        };

        /**
         * 返回当前线程的唯一的序列，如果第一次get，会先调用initialValue，后面看源码就了解了
         * @return
         */
        public static int get() {
            return threadId.get();
        }
    }

    static class ThreadId2 {
        /** 一个递增的序列，使用AtomicInger原子变量保证线程安全 */
        private static final AtomicInteger nextId = new AtomicInteger(0);

        /** 线程本地变量，为每个线程关联一个唯一的序号 */
        private static final ThreadLocal<Integer> threadId = new ThreadLocal<Integer>(){
            @Override
            protected Integer initialValue() {
                /** 相当于nextId++,由于nextId++这种操作是个复合操作而非原子操作，
                 会有线程安全问题(可能在初始化时就获取到相同的ID，所以使用原子变量 */
                return nextId.getAndIncrement();
            }
        };

        /**
         * 返回当前线程的唯一的序列，如果第一次get，会先调用initialValue，后面看源码就了解了
         * @return
         */
        public static int get() {
            return threadId.get();
        }
    }

}
